package com.DHH.wxPay;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;


import com.DHH.Util.ClientCustomSSL;

import com.DHH.Util.CodeUit;
import com.DHH.Util.MessageUtil;
import com.DHH.Util.UUIDHexGenerator;
import com.alibaba.fastjson.JSONObject;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


/**
 * 用户支付相关接口
 *
 * @author tieminPan
 *
 */

public class PayDao {

	private final static String APPID = "wx27049d040b7f6366"; // 小程序appid
	private final static String MCH_ID = "1484560402"; // 商户号
	private final static String OP_USER_ID = "1484560402"; // 操作员
	//&key=chongqingdahuihuiyouxiangongsi11
	private final static String KEY = "&key=DaHuiHuiBikeSecret12345678912345"; // 商户支付密钥
	private final static String URLS = "https://api.mch.weixin.qq.com/secapi/pay/refund"; // 统一退款地址
	private final static String URLSS = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 统一下单API接口链接
	private final static String URLSSS = "https://api.mch.weixin.qq.com/pay/orderquery";// 统一查询API接口链接
	private final static String NOTIFY_URL = "https://wxapi.exbike.cn/api/wxnotice"; // 支付通知地址
	private final static String TRADE_TYPE = "JSAPI"; // 交易类型

	/**
	 * 用户退款
	 *
	 * @param out_trade_no
	 *            商户单号
	 * @param total_fee
	 *            订单总金额
	 * @param refund_fee
	 *            订单退款金额
	 * @return
	 */
	@SuppressWarnings("static-access")
	public boolean UserRefundMoney(String out_trade_no, String total_fee,
								   String refund_fee) {
		// 初始化订单退款失败
		boolean tag = false;
		// 随机字符串
		String nonce_str = UUIDHexGenerator.generate();
		// 商户退款单号,商户系统内部的退款单号，商户系统内部唯一，同一退款单号多次请求只退一笔
		String out_refund_no = nonce_str;

		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("appid", APPID);
		sParaTemp.put("mch_id", MCH_ID);
		sParaTemp.put("nonce_str", nonce_str);
		sParaTemp.put("out_trade_no", out_trade_no);
		sParaTemp.put("out_refund_no", out_refund_no);
		sParaTemp.put("total_fee", total_fee);
		sParaTemp.put("refund_fee", refund_fee);
		sParaTemp.put("op_user_id", OP_USER_ID);

		// 除去数组中的空值和签名参数
		Map<String, String> sPara = PayUtil.paraFilter(sParaTemp);
		// 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String prestr = PayUtil.createLinkString(sPara);

		// MD5运算生成签名
		String sign = PayUtil.sign(prestr, KEY, "utf-8").toUpperCase();
		PaycancelPo paycancelPo = new PaycancelPo();
		paycancelPo.setAppid(APPID);
		paycancelPo.setMch_id(MCH_ID);
		paycancelPo.setNonce_str(nonce_str);
		paycancelPo.setOut_trade_no(out_trade_no);
		paycancelPo.setOut_refund_no(out_refund_no);
		paycancelPo.setTotal_fee(total_fee);
		paycancelPo.setRefund_fee(refund_fee);
		paycancelPo.setOp_user_id(OP_USER_ID);
		paycancelPo.setSign(sign);

		String respXml = MessageUtil.MessageToXML(paycancelPo);
		// 打印respXml发现，得到的xml中有“__”不对，应该替换成“_”
		respXml = respXml.replace("__", "_");

		ClientCustomSSL CCSSLs = new ClientCustomSSL();
		String result = null;
		try {
			result = CCSSLs.payHttps(MCH_ID, URLS, respXml);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		InputStream in = null;
		try {
			in = new ByteArrayInputStream(result.getBytes("utf-8"));
		} catch (UnsupportedEncodingException e) {

			e.printStackTrace();
		}
		// 读取输入流
		SAXReader reader = new SAXReader();
		org.dom4j.Document document = null;
		try {
			document = reader.read(in);
		} catch (DocumentException e) {

			e.printStackTrace();
		}
		// 得到xml根元素
		Element root = document.getRootElement();
		// 得到根元素的所有子节点
		@SuppressWarnings("unchecked")
		List<Element> elementList = root.elements();
		for (Element element : elementList) {
			map.put(element.getName(), element.getText());
		}

		if ("FAIL".equals(map.get("result_code"))) { // 退款失败
			tag = false;

		} else if ("SUCCESS".equals(map.get("result_code"))) {
			tag = true;
		}
		return tag;
	}

	/**
	 * 用户调用支付接口
	 *
	 * @param total_fee
	 *            支付金额
	 * @param title
	 *            商品详情(标题)
	 * @param openid
	 *            微信用户唯一标识
	 * @param spbill_create_ip
	 *            用户端ip
	 * @return
	 */
	public String UserPayLaunchMoney(String total_fee, String title,
									 String openid, String spbill_create_ip) {

		JSONObject JsonObject=new JSONObject();

		// 返回商户订单号
		String Results = null;
		// 随机字符串
		String nonce_str = UUIDHexGenerator.generate();
		// 当前时间
		String today = new SimpleDateFormat("yyyyMMddHHmmss")
				.format(new Date());
		String code = PayUtil.createCode(8);
		// 商户订单号=商户号+当前时间+uuid
		String out_trade_no = MCH_ID + today + code;
		Map<String, String> sParaTemp = new HashMap<String, String>();

		sParaTemp.put("appid", APPID);
		sParaTemp.put("body", title);
		sParaTemp.put("mch_id", MCH_ID);
		sParaTemp.put("nonce_str", nonce_str);
		sParaTemp.put("notify_url", NOTIFY_URL);
		sParaTemp.put("openid", openid);
		sParaTemp.put("spbill_create_ip", spbill_create_ip);
		sParaTemp.put("out_trade_no", out_trade_no);
		sParaTemp.put("total_fee", total_fee);
		sParaTemp.put("trade_type", TRADE_TYPE);

		// 除去数组中的空值和签名参数
		Map<String, String> sPara = PayUtil.paraFilter(sParaTemp);
		// 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String prestr = PayUtil.createLinkString(sPara);

		// MD5运算生成签名
		String sign = PayUtil.sign(prestr, KEY, "utf-8").toUpperCase();
		PaymentPo paymentPo = new PaymentPo();
		paymentPo.setAppid(APPID);
		paymentPo.setMch_id(MCH_ID);
		paymentPo.setNonce_str(nonce_str);
		paymentPo.setBody(title);
		paymentPo.setOut_trade_no(out_trade_no);
		paymentPo.setTotal_fee(total_fee);
		paymentPo.setSpbill_create_ip(spbill_create_ip);
		paymentPo.setNotify_url(NOTIFY_URL);
		paymentPo.setTrade_type(TRADE_TYPE);
		paymentPo.setOpenid(openid);
		paymentPo.setSign(sign);

		// 打包要发送的xml
		String respXml = MessageUtil.messageToXML(paymentPo);
		// 打印respXml发现，得到的xml中有“__”不对，应该替换成“_”
		respXml = respXml.replace("__", "_");
		String result = PayUtil.httpRequest(URLSS, "POST", respXml);

		// 将解析结果存储在HashMap中
		Map<String, String> map = new TreeMap<String, String>(
				new Comparator<String>() {
					public int compare(String obj1, String obj2) {
						// 字典序排序
						return obj1.compareTo(obj2);
					}
				});

		InputStream in = null;

		try {
			in = new ByteArrayInputStream(result.getBytes("utf-8"));
		} catch (UnsupportedEncodingException e1) {

			e1.printStackTrace();
		}
		// 读取输入流
		SAXReader reader = new SAXReader();
		org.dom4j.Document document;

		try {
			document = reader.read(in);
			// 得到xml根元素
			Element root = document.getRootElement();
			// 得到根元素的所有子节点
			@SuppressWarnings("unchecked")
			List<Element> elementList = root.elements();
			for (Element element : elementList) {
				map.put(element.getName(), element.getText());
			}
		} catch (DocumentException e) {

			e.printStackTrace();
		}

		// 对map键值对进行字符串处理,拿出最终需要进行MD5签名的字符串
		Set<String> keySet = map.keySet();
		Iterator<String> iter = keySet.iterator();

		String signValue = "";	// 定义最后需要签名的字符串
		String signKey = "";	// map中签名的key值
		while (iter.hasNext()) {
			String key = iter.next();
			if (map.get(key)==null || key.equals("sign")){
				if (key.equals("sign")){
					signKey = map.get(key);
					continue;
				}
				continue;
			}
			else{
				signValue += key+"="+map.get(key)+"&";
			}
		}
		// 签名字符串加上key
		signValue = signValue.substring(0, signValue.length() - 1);
		signValue = signValue + KEY;

		// 两次签名验证是否相等
		CodeUit md5 = new CodeUit();
		String signMD5 = md5.getMd5(signValue, 32);

		if (signMD5.equals(signKey)){

		}
		// 签名验证失败
		else{
			System.out.println("签名验证失败");
			result = null;
			return result;
		}

		if ("FAIL".equals(map.get("result_code"))) {
			// 调用支付接口失败
			System.out.println("调用支付接口失败");
			return Results;

		} else if ("SUCCESS".equals(map.get("result_code"))) {
			// 调用支付接口成功
			String nonceStr=UUIDHexGenerator.generate();
			JsonObject.put("nonceStr", nonceStr);//nonceStr:随机字符串，长度为32个字符以下。
			String prepay_id = map.get("prepay_id");//返回的预付单信息
			JsonObject.put("package", "prepay_id="+prepay_id);//统一下单接口返回的 prepay_id 参数值，提交格式如：prepay_id=*
			JsonObject.put("out_trade_no", out_trade_no);//商户订单号
			Long timeStamp= System.currentTimeMillis()/1000;
			JsonObject.put("timeStamp", timeStamp+"");//timeStamp:时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
			String appid=map.get("appid");
			String stringSignTemp = "appId="+appid+"&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
			//再次签名
			String paySign=PayUtil.sign(stringSignTemp,KEY , "utf-8").toUpperCase();
			JsonObject.put("paySign", paySign);//签名


			System.out.println("返回类型:== "+JsonObject);

			Results = JsonObject.toString();

		}

		return Results;
	}



	/**
	 * 查询用户支付状态
	 * @param out_trade_no
	 * @return
	 */
	public boolean UserPayQuery(String out_trade_no) {
		// 随机字符串
		String nonce_str = UUIDHexGenerator.generate();
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("appid", APPID);
		sParaTemp.put("mch_id", MCH_ID);
		sParaTemp.put("nonce_str", nonce_str);
		sParaTemp.put("out_trade_no", out_trade_no);

		// 除去数组中的空值和签名参数
		Map<String, String> sPara = PayUtil.paraFilter(sParaTemp);
		String prestr = PayUtil.createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		// MD5运算生成签名
		String sign = PayUtil.sign(prestr, KEY, "utf-8").toUpperCase();

		PaymentPo paymentPo = new PaymentPo();
		paymentPo.setAppid(APPID);
		paymentPo.setMch_id(MCH_ID);
		paymentPo.setNonce_str(nonce_str);
		paymentPo.setOut_trade_no(out_trade_no);
		paymentPo.setSign(sign);

		// 打包要发送的xml
		String respXml = MessageUtil.messageToXML(paymentPo);
		// 打印respXml发现，得到的xml中有“__”不对，应该替换成“_”
		respXml = respXml.replace("__", "_");
		String result = PayUtil.httpRequest(URLSSS, "POST", respXml);
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		InputStream in = null;
		try {
			in = new ByteArrayInputStream(result.getBytes("utf-8"));
		} catch (UnsupportedEncodingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		// 读取输入流
		SAXReader reader = new SAXReader();
		org.dom4j.Document document;
		try {
			document = reader.read(in);
			// 得到xml根元素
			Element root = document.getRootElement();
			// 得到根元素的所有子节点
			@SuppressWarnings("unchecked")
			List<Element> elementList = root.elements();
			for (Element element : elementList) {
				map.put(element.getName(), element.getText());
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		if ("SUCCESS".equals(map.get("trade_state"))) {
			// 查询支付状态为成功
			return true;
		} else {
			return false;
		}

	}

	// 单元测试
	public static void main(String[] args) {

		PayDao p=new PayDao();
		String out_trade_no="14845604022017072118382365183657";
		if(p.UserRefundMoney(out_trade_no, "19900", "19900")){
			System.out.println("ok");
		}else{
			System.out.println("no");
		}


	}
}
